package com.gzc.just.play.last.war.sceneserver.gameobject.unit;

import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObject;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectCamp;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectType;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.Vector3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 游戏单位基类 - 具有战斗属性的游戏对象
 * 
 * 对应C++ SSGameUnit
 * 继承自GameObject，表示可以在战斗中参与的单位（英雄、NPC、士兵等）
 * 
 * @author AI Assistant
 * @version 1.0.0
 * @since 2025-11-22
 */
public abstract class GameUnit extends GameObject {
    
    private static final Logger log = LoggerFactory.getLogger(GameUnit.class);
    private static final long serialVersionUID = 1L;

    // 战斗属性
    private int maxHealth;              // 最大生命值
    private int currentHealth;          // 当前生命值
    private int maxMana;                // 最大魔力
    private int currentMana;            // 当前魔力
    
    // 攻防属性
    private double attack;              // 攻击力
    private double defense;             // 防御力
    private double speed;               // 速度
    private double criticalRate;        // 暴击率（0-1）
    
    // 状态
    private boolean alive;              // 是否活着
    private boolean dead;               // 是否已死亡
    private boolean underControl;       // 是否被控制
    private boolean silent;             // 是否沉默（无法施法）
    private long deathTime;             // 死亡时间
    
    // 移动
    private boolean moving;             // 是否正在移动
    private double moveSpeed;           // 移动速度
    
    // 战斗相关
    private GameUnit currentTarget;     // 当前目标
    private int totalDamageDealt;       // 总伤害输出
    private int totalDamageReceived;    // 总伤害承受
    private int killCount;              // 击杀数
    private int deathCount;             // 死亡次数
    
    // 监听器
    private transient List<GameUnitListener> listeners;
    
    // 恢复管理
    private long lastHealthRecoverTime; // 最后恢复生命值的时间
    private long lastManaRecoverTime;   // 最后恢复魔力的时间
    private double healthRecoverRate;   // 生命恢复速率（每秒）
    private double manaRecoverRate;     // 魔力恢复速率（每秒）

    // Getter和Setter方法
    public int getMaxHealth() {
        return maxHealth;
    }
    
    public void setMaxHealth(int maxHealth) {
        this.maxHealth = maxHealth;
    }
    
    public int getCurrentHealth() {
        return currentHealth;
    }
    
    public void setCurrentHealth(int currentHealth) {
        this.currentHealth = currentHealth;
    }
    
    public int getMaxMana() {
        return maxMana;
    }
    
    public void setMaxMana(int maxMana) {
        this.maxMana = maxMana;
    }
    
    public int getCurrentMana() {
        return currentMana;
    }
    
    public void setCurrentMana(int currentMana) {
        this.currentMana = currentMana;
    }
    
    public double getAttack() {
        return attack;
    }
    
    public void setAttack(double attack) {
        this.attack = attack;
    }
    
    public double getDefense() {
        return defense;
    }
    
    public void setDefense(double defense) {
        this.defense = defense;
    }
    
    public double getSpeed() {
        return speed;
    }
    
    public void setSpeed(double speed) {
        this.speed = speed;
    }
    
    public double getCriticalRate() {
        return criticalRate;
    }
    
    public void setCriticalRate(double criticalRate) {
        this.criticalRate = criticalRate;
    }
    
    public boolean isAlive() {
        return alive;
    }
    
    public void setAlive(boolean alive) {
        this.alive = alive;
    }
    
    public boolean isDead() {
        return dead;
    }
    
    public void setDead(boolean dead) {
        this.dead = dead;
    }
    
    public boolean isUnderControl() {
        return underControl;
    }
    
    public void setUnderControl(boolean underControl) {
        this.underControl = underControl;
    }
    
    public boolean isSilent() {
        return silent;
    }
    
    public void setSilent(boolean silent) {
        this.silent = silent;
    }
    
    public long getDeathTime() {
        return deathTime;
    }
    
    public void setDeathTime(long deathTime) {
        this.deathTime = deathTime;
    }
    
    public boolean isMoving() {
        return moving;
    }
    
    public void setMoving(boolean moving) {
        this.moving = moving;
    }
    
    public double getMoveSpeed() {
        return moveSpeed;
    }
    
    public void setMoveSpeed(double moveSpeed) {
        this.moveSpeed = moveSpeed;
    }
    
    public GameUnit getCurrentTarget() {
        return currentTarget;
    }
    
    public void setCurrentTarget(GameUnit currentTarget) {
        this.currentTarget = currentTarget;
    }
    
    public int getTotalDamageDealt() {
        return totalDamageDealt;
    }
    
    public void setTotalDamageDealt(int totalDamageDealt) {
        this.totalDamageDealt = totalDamageDealt;
    }
    
    public int getTotalDamageReceived() {
        return totalDamageReceived;
    }
    
    public void setTotalDamageReceived(int totalDamageReceived) {
        this.totalDamageReceived = totalDamageReceived;
    }
    
    public int getKillCount() {
        return killCount;
    }
    
    public void setKillCount(int killCount) {
        this.killCount = killCount;
    }
    
    public int getDeathCount() {
        return deathCount;
    }
    
    public void setDeathCount(int deathCount) {
        this.deathCount = deathCount;
    }
    
    public List<GameUnitListener> getListeners() {
        return listeners;
    }
    
    public void setListeners(List<GameUnitListener> listeners) {
        this.listeners = listeners;
    }
    
    public long getLastHealthRecoverTime() {
        return lastHealthRecoverTime;
    }
    
    public void setLastHealthRecoverTime(long lastHealthRecoverTime) {
        this.lastHealthRecoverTime = lastHealthRecoverTime;
    }
    
    public long getLastManaRecoverTime() {
        return lastManaRecoverTime;
    }
    
    public void setLastManaRecoverTime(long lastManaRecoverTime) {
        this.lastManaRecoverTime = lastManaRecoverTime;
    }
    
    public double getHealthRecoverRate() {
        return healthRecoverRate;
    }
    
    public void setHealthRecoverRate(double healthRecoverRate) {
        this.healthRecoverRate = healthRecoverRate;
    }
    
    public double getManaRecoverRate() {
        return manaRecoverRate;
    }
    
    public void setManaRecoverRate(double manaRecoverRate) {
        this.manaRecoverRate = manaRecoverRate;
    }

    /**
     * 构造函数
     */
    public GameUnit(long objectId, GameObjectType objectType, GameObjectCamp camp, 
                    int maxHealth, int maxMana, double attack, double defense, double speed) {
        super(objectId, objectType, camp);
        this.maxHealth = maxHealth;
        this.currentHealth = maxHealth;
        this.maxMana = maxMana;
        this.currentMana = maxMana;
        this.attack = attack;
        this.defense = defense;
        this.speed = speed;
        this.criticalRate = 0.0;
        
        this.alive = true;
        this.dead = false;
        this.underControl = false;
        this.silent = false;
        this.deathTime = 0;
        
        this.moving = false;
        this.moveSpeed = speed;
        
        this.currentTarget = null;
        this.totalDamageDealt = 0;
        this.totalDamageReceived = 0;
        this.killCount = 0;
        this.deathCount = 0;
        
        this.listeners = new CopyOnWriteArrayList<>();
        
        this.lastHealthRecoverTime = System.currentTimeMillis();
        this.lastManaRecoverTime = System.currentTimeMillis();
        this.healthRecoverRate = 1.0;  // 每秒1点
        this.manaRecoverRate = 1.0;    // 每秒1点
    }

    /**
     * 初始化单位
     */
    @Override
    public void initialize() {
        log.info("初始化GameUnit: {}", getObjectId());
        this.alive = true;
        this.dead = false;
        this.currentHealth = maxHealth;
        this.currentMana = maxMana;
        this.activate();
    }

    /**
     * 销毁单位
     */
    @Override
    public void destroy() {
        log.info("销毁GameUnit: {}", getObjectId());
        this.alive = false;
        this.dead = true;
        this.listeners.clear();
        this.deactivate();
    }

    /**
     * 处理心跳（包含恢复逻辑）
     */
    @Override
    public void processHeartbeat(long currentTime, long deltaTime) {
        if (!isAlive() || !alive) {
            return;
        }

        // 处理恢复
        recoverHealth(currentTime, deltaTime);
        recoverMana(currentTime, deltaTime);
        
        // 处理移动
        if (moving) {
            updateMove(currentTime, deltaTime);
        }
        
        // 检查死亡状态
        checkDeadState();
    }

    /**
     * 受到伤害
     */
    public void takeDamage(int damage) {
        if (!alive || dead) {
            return;
        }

        if (damage < 0) {
            damage = 0;
        }

        int actualDamage = Math.max(1, damage - (int)defense);
        currentHealth -= actualDamage;
        totalDamageReceived += actualDamage;

        log.debug("单位 {} 受到伤害 {}, 当前血量 {}", getObjectId(), actualDamage, currentHealth);

        notifyDamageTaken(actualDamage);

        if (currentHealth <= 0) {
            die();
        }
    }

    /**
     * 恢复生命值
     */
    public void restoreHealth(int amount) {
        if (!alive || dead) {
            return;
        }

        if (amount <= 0) {
            return;
        }

        int oldHealth = currentHealth;
        currentHealth = Math.min(currentHealth + amount, maxHealth);
        int actualRestore = currentHealth - oldHealth;

        if (actualRestore > 0) {
            log.debug("单位 {} 恢复生命值 {}, 当前血量 {}", getObjectId(), actualRestore, currentHealth);
            notifyHealthRestored(actualRestore);
        }
    }

    /**
     * 恢复魔力值
     */
    public void restoreMana(int amount) {
        if (!alive || dead) {
            return;
        }

        if (amount <= 0) {
            return;
        }

        int oldMana = currentMana;
        currentMana = Math.min(currentMana + amount, maxMana);
        int actualRestore = currentMana - oldMana;

        if (actualRestore > 0) {
            log.debug("单位 {} 恢复魔力 {}, 当前魔力 {}", getObjectId(), actualRestore, currentMana);
            notifyManaRestored(actualRestore);
        }
    }

    /**
     * 死亡
     */
    public void die() {
        if (dead) {
            return;
        }

        log.info("单位 {} 已死亡", getObjectId());
        this.alive = false;
        this.dead = true;
        this.deathTime = System.currentTimeMillis();
        this.currentHealth = 0;
        this.moving = false;
        this.deathCount++;

        notifyDead();
    }

    /**
     * 复活
     */
    public void revive(int healthPercent) {
        if (!dead) {
            return;
        }

        log.info("单位 {} 已复活", getObjectId());
        this.alive = true;
        this.dead = false;
        this.currentHealth = Math.max(1, (int)(maxHealth * healthPercent / 100.0));
        this.currentMana = maxMana;

        notifyRevived();
    }

    /**
     * 开始移动
     */
    public void startMove(Vector3 direction, double speed) {
        if (!alive || dead) {
            return;
        }

        this.moving = true;
        this.moveSpeed = Math.min(speed, this.speed);
        Vector3 normalized = direction.normalize();
        this.setDirection(normalized);

        log.debug("单位 {} 开始移动，方向: {}, 速度: {}", getObjectId(), normalized, moveSpeed);
    }

    /**
     * 停止移动
     */
    public void stopMove() {
        this.moving = false;
        log.debug("单位 {} 停止移动", getObjectId());
    }

    /**
     * 设置目标
     */
    public void setTarget(GameUnit target) {
        this.currentTarget = target;
        if (target != null) {
            log.debug("单位 {} 设置目标为 {}", getObjectId(), target.getObjectId());
        } else {
            log.debug("单位 {} 清除目标", getObjectId());
        }
    }

    /**
     * 加入击杀统计
     */
    public void addKill(GameUnit victim) {
        this.killCount++;
        log.debug("单位 {} 击杀了 {}, 总击杀数: {}", getObjectId(), victim.getObjectId(), killCount);
        notifyKillAchieved(victim);
    }

    /**
     * 是否为英雄
     */
    public boolean isHero() {
        return false;
    }

    /**
     * 是否为NPC
     */
    public boolean isNPC() {
        return false;
    }

    /**
     * 是否为士兵
     */
    public boolean isSoldier() {
        return false;
    }

    /**
     * 添加监听器
     */
    public void addListener(GameUnitListener listener) {
        if (listener != null && !listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    /**
     * 移除监听器
     */
    public void removeListener(GameUnitListener listener) {
        listeners.remove(listener);
    }

    // 内部方法

    /**
     * 生命值自动恢复
     */
    private void recoverHealth(long currentTime, long deltaTime) {
        if (currentHealth >= maxHealth) {
            return;
        }

        long timeSinceLastRecover = currentTime - lastHealthRecoverTime;
        if (timeSinceLastRecover >= 1000) { // 每秒恢复一次
            int recoverAmount = (int)(healthRecoverRate * timeSinceLastRecover / 1000.0);
            if (recoverAmount > 0) {
                restoreHealth(recoverAmount);
                lastHealthRecoverTime = currentTime;
            }
        }
    }

    /**
     * 魔力自动恢复
     */
    private void recoverMana(long currentTime, long deltaTime) {
        if (currentMana >= maxMana) {
            return;
        }

        long timeSinceLastRecover = currentTime - lastManaRecoverTime;
        if (timeSinceLastRecover >= 1000) { // 每秒恢复一次
            int recoverAmount = (int)(manaRecoverRate * timeSinceLastRecover / 1000.0);
            if (recoverAmount > 0) {
                restoreMana(recoverAmount);
                lastManaRecoverTime = currentTime;
            }
        }
    }

    /**
     * 更新移动
     */
    private void updateMove(long currentTime, long deltaTime) {
        Vector3 direction = this.getDirection();
        if (direction == null || direction.length() == 0) {
            return;
        }

        double moveDistance = moveSpeed * deltaTime / 1000.0;
        Vector3 movement = direction.scale((float)moveDistance);
        
        double newX = this.getPosX() + movement.getX();
        double newY = this.getPosY() + movement.getY();
        double newZ = this.getPosZ() + movement.getZ();
        
        this.setPosX(newX);
        this.setPosY(newY);
        this.setPosZ(newZ);

        notifyMoved();
    }

    /**
     * 检查死亡状态
     */
    protected abstract void checkDeadState();

    // 通知方法

    private void notifyDamageTaken(int damage) {
        listeners.forEach(listener -> listener.onDamageTaken(this, damage));
    }

    private void notifyHealthRestored(int amount) {
        listeners.forEach(listener -> listener.onHealthRestored(this, amount));
    }

    private void notifyManaRestored(int amount) {
        listeners.forEach(listener -> listener.onManaRestored(this, amount));
    }

    private void notifyDead() {
        listeners.forEach(listener -> listener.onDead(this));
    }

    private void notifyRevived() {
        listeners.forEach(listener -> listener.onRevived(this));
    }

    private void notifyMoved() {
        listeners.forEach(listener -> listener.onMoved(this));
    }

    private void notifyKillAchieved(GameUnit victim) {
        listeners.forEach(listener -> listener.onKillAchieved(this, victim));
    }

    /**
     * 获取属性值（用于通用属性访问）
     * @param type 属性类型
     * @return 属性值
     */
    public double getAttribute(com.gzc.just.play.last.war.sceneserver.attribute.AttributeType type) {
        if (type == null) {
            return 0;
        }
        
        switch (type) {
            case ATTACK:
                return attack;
            case DEFENSE:
                return defense;
            case SPEED:
                return speed;
            case MAX_HEALTH:
                return maxHealth;
            case CURRENT_HEALTH:
                return currentHealth;
            case MAX_MANA:
                return maxMana;
            case CURRENT_MANA:
                return currentMana;
            case CRITICAL_RATE:
                return criticalRate;
            case GOLD:
                // 这是一个占位符，实际的金币应该存储在其他地方
                return 0;
            default:
                return 0;
        }
    }

    /**
     * 修改属性值（用于通用属性修改）
     * @param type 属性类型
     * @param delta 变化量
     */
    public void modifyAttribute(com.gzc.just.play.last.war.sceneserver.attribute.AttributeType type, double delta) {
        if (type == null) {
            return;
        }
        
        switch (type) {
            case ATTACK:
                this.attack += delta;
                break;
            case DEFENSE:
                this.defense += delta;
                break;
            case SPEED:
                this.speed += delta;
                break;
            case MAX_HEALTH:
                this.maxHealth = Math.max(1, (int)(maxHealth + delta));
                if (currentHealth > maxHealth) {
                    currentHealth = maxHealth;
                }
                break;
            case CURRENT_HEALTH:
                this.currentHealth = Math.max(0, Math.min(maxHealth, (int)(currentHealth + delta)));
                break;
            case MAX_MANA:
                this.maxMana = Math.max(0, (int)(maxMana + delta));
                if (currentMana > maxMana) {
                    currentMana = maxMana;
                }
                break;
            case CURRENT_MANA:
                this.currentMana = Math.max(0, Math.min(maxMana, (int)(currentMana + delta)));
                break;
            case CRITICAL_RATE:
                this.criticalRate = Math.max(0, Math.min(1, criticalRate + delta));
                break;
            case GOLD:
                // 这是一个占位符，实际的金币应该存储在其他地方
                log.warn("尝试修改GameUnit中的金币属性，但此属性不在此类中管理");
                break;
        }
    }

    @Override
    public String toString() {
        return String.format("GameUnit{id=%d, type=%s, camp=%s, hp=%d/%d, alive=%b, dead=%b, kill=%d, death=%d}",
                getObjectId(), getObjectType(), getCamp(), currentHealth, maxHealth, alive, dead, killCount, deathCount);
    }
}
